﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.CodeDom;

namespace CodeDomHelper.CodeDom
{

    [Serializable()]
    public class NamespaceExp : CodeNamespace
    {
        
        public NamespaceExp() : base() 
        { 
        
        }

        public NamespaceExp(string name) : base(name) 
        { 
        
        }


        #region Parse namespaces

        public List<CodeNamespaceImport> GetNamespaces(int min, string currentNamespace)
        {
            Dictionary<String, int> l = new Dictionary<String, int>();
            GetNamespaces(this.Types, l);

            List<CodeNamespaceImport> l2 = new List<CodeNamespaceImport>();

            foreach (var n in l)
                if (n.Value >= min &&  n.Key != currentNamespace)
                    l2.Add(new CodeNamespaceImport(n.Key));

            return l2;
        }

        private void GetNamespaces(CodeTypeReference code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            string[] n = code.BaseType.Split('.');
            Array.Resize(ref n, n.Length - 1);

            string j = string.Join(".", n);

            // ------------------------ Add ------------------------
            if (j == "System.Void" || String.IsNullOrEmpty(j))
                return;

            if (!l.ContainsKey(j))
                l.Add(j, 0);

            var i = l[j];
            i++;
            l[j] = i;

        }

        private void GetNamespaces(CodeTypeDeclarationCollection code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            foreach (CodeTypeDeclaration item in code)
                GetNamespaces(item, l);
        }

        private void GetNamespaces(CodeTypeDeclaration code, Dictionary<String, int> l)
        {
            if (code == null)
                return;
            GetNamespaces(code.BaseTypes, l);
            GetNamespace(code.Members, l);
            GetNamespaces(code.TypeParameters, l);
        }

        private void GetNamespaces(CodeTypeParameterCollection code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            foreach (CodeTypeParameter item in code)
                GetNamespaces(item, l);
        }

        private void GetNamespaces(CodeTypeParameter code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Constraints, l);
        }

        private void GetNamespace(CodeTypeMemberCollection code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            foreach (CodeTypeMember item in code)
            {

                if (item is CodeMemberEvent)
                    GetNamespaces(item as CodeMemberEvent, l);

                if (item is CodeMemberField)
                    GetNamespaces(item as CodeMemberField, l);

                if (item is CodeMemberMethod)
                    GetNamespaces(item as CodeMemberMethod, l);

                if (item is CodeTypeDeclaration)
                    GetNamespaces(item as CodeTypeDeclaration, l);
            }
        }

        private void GetNamespaces(CodeMemberEvent code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Type, l);
            GetNamespaces(code.ImplementationTypes, l);
        }

        private void GetNamespaces(CodeMemberField code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Type, l);
            GetNamespace(code.InitExpression, l);
        }

        private void GetNamespaces(CodeMemberMethod code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.TypeParameters, l);
            GetNamespaces(code.Statements, l);
            GetNamespaces(code.ReturnType, l);
            GetNamespaces(code.ReturnTypeCustomAttributes, l);
            GetNamespaces(code.PrivateImplementationType, l);
            GetNamespaces(code.Parameters, l);
            GetNamespaces(code.ImplementationTypes, l);
            GetNamespaces(code.CustomAttributes, l);
  
        }

        private void GetNamespaces(CodeParameterDeclarationExpressionCollection code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            foreach (CodeParameterDeclarationExpression item in code)
                GetNamespaces(item, l);
        }

        private void GetNamespaces(CodeAttributeDeclarationCollection code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            foreach (CodeAttributeDeclaration item in code)
                GetNamespaces(item, l);       
        }

        private void GetNamespaces(CodeAttributeDeclaration code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Arguments, l);
            GetNamespaces(code.AttributeType, l);
        }

        private void GetNamespaces(CodeAttributeArgumentCollection code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            foreach (CodeAttributeArgument item in code)
               GetNamespaces(item, l);
        }

        private void GetNamespaces(CodeAttributeArgument code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.Value, l);
        }

        private void GetNamespaces(CodeStatementCollection code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            foreach (CodeStatement item in code)
                GetNamespace(item, l);
                
        }

        private void GetNamespaces(CodeTypeReferenceCollection code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            foreach (CodeTypeReference item in code)
                GetNamespaces(item, l);
        }

        private void GetNamespace(CodeExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            if (code is CodeArrayCreateExpression)
                GetNamespaces(code as CodeArrayCreateExpression, l);

            if (code is CodeArrayIndexerExpression)
                GetNamespaces(code as CodeArrayIndexerExpression, l);

            if (code is CodeBinaryOperatorExpression)
                GetNamespaces(code as CodeBinaryOperatorExpression, l);

            if (code is CodeCastExpression)
                GetNamespaces(code as CodeCastExpression, l);

            if (code is CodeDefaultValueExpression)
                GetNamespaces(code as CodeDefaultValueExpression, l);

            if (code is CodeDelegateCreateExpression)
                GetNamespaces(code as CodeDelegateCreateExpression, l);

            if (code is CodeDelegateInvokeExpression)
                GetNamespaces(code as CodeDelegateInvokeExpression, l);

            if (code is CodeDirectionExpression)
                GetNamespaces(code as CodeDirectionExpression, l);

            if (code is CodeEventReferenceExpression)
                GetNamespaces(code as CodeEventReferenceExpression, l);

            if (code is CodeFieldReferenceExpression)
                GetNamespaces(code as CodeFieldReferenceExpression, l);

            if (code is CodeIndexerExpression)
                GetNamespaces(code as CodeIndexerExpression, l);

            if (code is CodeMethodInvokeExpression)
                GetNamespaces(code as CodeMethodInvokeExpression, l);

            if (code is CodeMethodReferenceExpression)
                GetNamespaces(code as CodeMethodReferenceExpression, l);

            if (code is CodeObjectCreateExpression)
                GetNamespaces(code as CodeObjectCreateExpression, l);

            if (code is CodeParameterDeclarationExpression)
                GetNamespaces(code as CodeParameterDeclarationExpression, l);

            if (code is CodePropertyReferenceExpression)
                GetNamespaces(code as CodePropertyReferenceExpression, l);

            if (code is CodeTypeOfExpression)
                GetNamespaces(code as CodeTypeOfExpression, l);

            if (code is CodeTypeReferenceExpression)
                GetNamespaces(code as CodeTypeReferenceExpression, l);

        }

        private void GetNamespaces(CodeTypeReferenceExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Type, l);
        }

        private void GetNamespaces(CodeTypeOfExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Type, l);
        }

        private void GetNamespaces(CodePropertyReferenceExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.TargetObject, l);
        }

        private void GetNamespaces(CodeParameterDeclarationExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Type, l);
        }

        private void GetNamespaces(CodeObjectCreateExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Parameters, l);
        }

        private void GetNamespaces(CodeExpressionCollection code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            foreach (CodeExpression item in code)
                GetNamespace(item, l);
        }

        private void GetNamespaces(CodeMethodReferenceExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.TargetObject, l);
            GetNamespaces(code.TypeArguments, l);
        }

        private void GetNamespaces(CodeMethodInvokeExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Method, l);
            GetNamespaces(code.Parameters, l);
        }

        private void GetNamespaces(CodeIndexerExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.TargetObject, l);
            GetNamespaces(code.Indices, l);
        }

        private void GetNamespaces(CodeFieldReferenceExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.TargetObject, l);
        }

        private void GetNamespaces(CodeEventReferenceExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.TargetObject, l);
        }

        private void GetNamespaces(CodeDirectionExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.Expression, l);
        }

        private void GetNamespaces(CodeDelegateInvokeExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Parameters, l);
            GetNamespace(code.TargetObject, l);
        }

        private void GetNamespaces(CodeDelegateCreateExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.DelegateType, l);
            GetNamespace(code.TargetObject, l);
        }

        private void GetNamespaces(CodeDefaultValueExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Type, l);
        }

        private void GetNamespaces(CodeCastExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.Expression, l);
            GetNamespaces(code.TargetType, l);
        }

        private void GetNamespaces(CodeBinaryOperatorExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.Left, l);
            GetNamespace(code.Right, l);
        }

        private void GetNamespaces(CodeArrayIndexerExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Indices, l);
            GetNamespace(code.TargetObject, l);
        }

        private void GetNamespaces(CodeArrayCreateExpression code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.CreateType, l);
            GetNamespaces(code.Initializers, l);
            GetNamespace(code.SizeExpression, l);
        }

        private void GetNamespace(CodeStatement code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            if (code is CodeAssignStatement)
                GetNamespaces(code as CodeAssignStatement, l);

            if (code is CodeAttachEventStatement)
                GetNamespaces(code as CodeAttachEventStatement, l);

            if (code is CodeConditionStatement)
                GetNamespaces(code as CodeConditionStatement, l);

            if (code is CodeExpressionStatement)
                GetNamespaces(code as CodeExpressionStatement, l);

            if (code is CodeIterationStatement)
                GetNamespaces(code as CodeIterationStatement, l);

            if (code is CodeLabeledStatement)
                GetNamespaces(code as CodeLabeledStatement, l);

            if (code is CodeMethodReturnStatement)
                GetNamespaces(code as CodeMethodReturnStatement, l);

            if (code is CodeRemoveEventStatement)
                GetNamespaces(code as CodeRemoveEventStatement, l);

            if (code is CodeThrowExceptionStatement)
                GetNamespaces(code as CodeThrowExceptionStatement, l);

            if (code is CodeTryCatchFinallyStatement)
                GetNamespaces(code as CodeTryCatchFinallyStatement, l);

            if (code is CodeVariableDeclarationStatement)
                GetNamespaces(code as CodeVariableDeclarationStatement, l);

        }

        private void GetNamespaces(CodeVariableDeclarationStatement code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.InitExpression, l);
            GetNamespaces(code.Type, l);
        }

        private void GetNamespaces(CodeTryCatchFinallyStatement code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.CatchClauses, l);
            GetNamespaces(code.FinallyStatements, l);
            GetNamespaces(code.TryStatements, l);
        }

        private void GetNamespaces(CodeCatchClauseCollection code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            foreach (CodeCatchClause item in code)
                GetNamespaces(item, l);
        }

        private void GetNamespaces(CodeCatchClause code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.CatchExceptionType, l);
            GetNamespaces(code.Statements, l);
        }

        private void GetNamespaces(CodeThrowExceptionStatement code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.ToThrow, l);
        }

        private void GetNamespaces(CodeRemoveEventStatement code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespaces(code.Event, l);
            GetNamespace(code.Listener, l);
        }

        private void GetNamespaces(CodeMethodReturnStatement code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.Expression, l);
        }

        private void GetNamespaces(CodeLabeledStatement code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.Statement, l);
        }

        private void GetNamespaces(CodeIterationStatement code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.IncrementStatement, l);
            GetNamespace(code.InitStatement, l);
            GetNamespaces(code.Statements, l);
            GetNamespace(code.TestExpression, l);
        }

        private void GetNamespaces(CodeExpressionStatement code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.Expression, l);
        }

        private void GetNamespaces(CodeConditionStatement code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.Condition, l);
            GetNamespaces(code.FalseStatements, l);
            GetNamespaces(code.TrueStatements, l);
        }

        private void GetNamespaces(CodeAttachEventStatement code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.Listener, l);
            GetNamespaces(code.Event, l);
        }

        private void GetNamespaces(CodeAssignStatement code, Dictionary<String, int> l)
        {
            if (code == null)
                return;

            GetNamespace(code.Left, l);
            GetNamespace(code.Right, l);
        }

        
        #endregion

    }

}
